package cn.edu.xmu.datamining.tangzk.mralgos.pagerank;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Writable;

/**
 * 
 * @version 2013-8-4
 * @author tangzk
 * @Reviewer
 * 
 */
public class PageRankNodeValueWritable implements Writable {

	private boolean isNode;
	// the pagerank value of source -> key
	private float pagerank;
	// the outgoing nodes
	private List<Integer> adjNodes = new ArrayList<Integer>();
	private int len;

	public PageRankNodeValueWritable() {
	}

	public PageRankNodeValueWritable(float pagerank, String adjStr) {
		this.isNode = true; // structure info
		this.pagerank = pagerank;
		if (!"".equals(adjStr)) {
			String[] ids = adjStr.split(",");
			for (String id : ids) {
				this.adjNodes.add(Integer.parseInt(id));
			}
		}
	}

	public PageRankNodeValueWritable(float pagerank, int len) {
		// pagerank info
		this.isNode = false;
		this.pagerank = pagerank;
		// need to calculate the normalized pagerank =
		// pagerank / source outdgree(len)
		this.len = len;
	}

	@Override
	public void write(DataOutput out) throws IOException {
		out.writeBoolean(this.isNode);
		out.writeFloat(pagerank);
		if (this.isNode) {
			out.writeInt(this.adjNodes.size());
			for (int i : this.adjNodes) {
				out.writeInt(i);
			}
		} else {
			out.writeInt(this.len);
		}
	}

	@Override
	public void readFields(DataInput in) throws IOException {
		this.isNode = in.readBoolean();
		this.pagerank = in.readFloat();
		if (this.isNode) {
			int l = in.readInt();
			this.adjNodes.clear();
			for (int i = 0; i < l; i++) {
				this.adjNodes.add(in.readInt());
			}
		} else {
			this.len = in.readInt();
		}
	}

	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof PageRankNodeValueWritable)) {
			return false;
		}
		PageRankNodeValueWritable node = (PageRankNodeValueWritable) obj;
		if (this.isNode != node.isNode
				|| Float.compare(this.pagerank, node.pagerank) != 0) {
			return false;
		}
		if (isNode) {
			return Arrays.equals(this.adjNodes.toArray(),
					node.adjNodes.toArray());
		} else {
			return this.len == node.len;
		}
	}

	@Override
	public int hashCode() {
		int code = (int) this.pagerank;
		code = (int) this.pagerank * 31;
		if (isNode) {
			for (int i : this.adjNodes) {
				code = code * 591 + 17;
			}
		} else {
			code = code * 591 + len;
		}
		return code;
	}

	@Override
	public String toString() {
		return (this.isNode ? 0 : 1) + ", " + this.pagerank + ", "
				+ (this.isNode ? this.adjNodes : this.len);
	}

	public float getPagerank() {
		return pagerank;
	}

	public void setPagerank(float pagerank) {
		this.pagerank = pagerank;
	}

	public boolean isNode() {
		return isNode;
	}

	public void setNode(boolean isNode) {
		this.isNode = isNode;
	}

	public List<Integer> getAdjNodes() {
		return adjNodes;
	}

	public void setAdjNodes(List<Integer> adjNodes) {
		this.adjNodes = adjNodes;
	}

	public int getLen() {
		return len;
	}

	public void setLen(int len) {
		this.len = len;
	}

}
